// Copyright (c) 2023 Hemashushu <hippospark@gmail.com>, All rights reserved.
//
// This Source Code Form is subject to the terms of
// the Mozilla Public License version 2.0 and additional exceptions,
// more details in file LICENSE, LICENSE.additional and CONTRIBUTING.

#[repr(u16)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum Opcode {
    //
    // immediate
    //
    // i32_imm, // fn (imm) -> value
    // i64_imm, // fn (imm) -> value
    // f32_imm, // fn (imm) -> value
    // f64_imm, // fn (imm) -> value

    //
    // local variables
    //
    local_load64_i64,   // fn ($local_name, offset) -> value
    local_load64_f64,   // ...
    local_load64_i32_s, // ...
    local_load64_i32_u, // ...
    local_load64_i16_s, // ...
    local_load64_i16_u, // ...
    local_load64_i8_s,  // ...
    local_load64_i8_u,  // ...
    local_load32_i32,   // ...
    local_load32_f32,   // ...
    local_load32_i16_s, // ...
    local_load32_i16_u, // ...
    local_load32_i8_s,  // ...
    local_load32_i8_u,  // ...
    local_store64,      // fn ($local_name, offset, value)
    local_store32,      // ...
    local_store16,      // ...
    local_store8,       // ...

    //
    // data
    //
    data_load64_i64,   // fn ($data_name, offset) -> value
    data_load64_f64,   // ...
    data_load64_i32_s, // ...
    data_load64_i32_u, // ...
    data_load64_i16_s, // ...
    data_load64_i16_u, // ...
    data_load64_i8_s,  // ...
    data_load64_i8_u,  // ...
    data_load32_i32,   // ...
    data_load32_f32,   // ...
    data_load32_i16_s, // ...
    data_load32_i16_u, // ...
    data_load32_i8_s,  // ...
    data_load32_i8_u,  // ...
    data_store64,      // fn ($data_name, offset, value)
    data_store32,      // ...
    data_store16,      // ...
    data_store8,       // ...

    //
    // memory
    //
    memory_load64_i64,   // fn (address, offset) -> value
    memory_load64_f64,   // ...
    memory_load64_i32_s, // ...
    memory_load64_i32_u, // ...
    memory_load64_i16_s, // ...
    memory_load64_i16_u, // ...
    memory_load64_i8_s,  // ...
    memory_load64_i8_u,  // ...
    memory_load32_i32,   // ...
    memory_load32_f32,   // ...
    memory_load32_i16_s, // ...
    memory_load32_i16_u, // ...
    memory_load32_i8_s,  // ...
    memory_load32_i8_u,  // ...
    memory_store64,      // fn (address, offset, value)
    memory_store32,      // ...
    memory_store16,      // ...
    memory_store8,       // ...

    //
    // conversion
    //

    // reduce i64 to i32
    i32_truncate_i64, // fn (src) -> value

    // extend i32 to i64
    i64_extend_i32_s, // fn (src) -> value
    i64_extend_i32_u, // fn (src) -> value

    // float demote and promote
    f32_demote_f64,  // fn (src) -> value
    f64_promote_f32, // fn (src) -> value

    // convert float to int
    i32_convert_f32_s, // fn (src) -> value
    i32_convert_f32_u, // ...
    i32_convert_f64_s, // ...
    i32_convert_f64_u, // ...
    i64_convert_f32_s, // ...
    i64_convert_f32_u, // ...
    i64_convert_f64_s, // ...
    i64_convert_f64_u, // ...

    // convert int to float
    f32_convert_i32_s, // fn (src) -> value
    f32_convert_i32_u, // ...
    f32_convert_i64_s, // ...
    f32_convert_i64_u, // ...
    f64_convert_i32_s, // ...
    f64_convert_i32_u, // ...
    f64_convert_i64_s, // ...
    f64_convert_i64_u, // ...

    // saturation convert float to int
    i32_sat_convert_f32_s, // fn (src) -> value
    i32_sat_convert_f32_u, // ...
    i32_sat_convert_f64_s, // ...
    i32_sat_convert_f64_u, // ...
    i64_sat_convert_f32_s, // ...
    i64_sat_convert_f32_u, // ...
    i64_sat_convert_f64_s, // ...
    i64_sat_convert_f64_u, // ...

    // reinterpret
    i32_reinterpret_f32,
    i64_reinterpret_f64,
    f32_reinterpret_i32,
    f64_reinterpret_i64,

    //
    // comparsion
    //
    i32_eqz,  // fn (src) -> value
    i32_nez,  // fn (src) -> value
    i32_eq,   // fn (left, right) -> value
    i32_ne,   // ...
    i32_lt_s, // ...
    i32_lt_u, // ...
    i32_gt_s, // ...
    i32_gt_u, // ...
    i32_le_s, // ...
    i32_le_u, // ...
    i32_ge_s, // ...
    i32_ge_u, // ...

    i64_eqz,  // fn (src) -> value
    i64_nez,  // fn (src) -> value
    i64_eq,   // fn (left, right) -> value
    i64_ne,   // ...
    i64_lt_s, // ...
    i64_lt_u, // ...
    i64_gt_s, // ...
    i64_gt_u, // ...
    i64_le_s, // ...
    i64_le_u, // ...
    i64_ge_s, // ...
    i64_ge_u, // ...

    f32_eq, // fn (left, right) -> value
    f32_ne, // ...
    f32_lt, // ...
    f32_gt, // ...
    f32_le, // ...
    f32_ge, // ...

    f64_eq, // fn (left, right) -> value
    f64_ne, // ...
    f64_lt, // ...
    f64_gt, // ...
    f64_le, // ...
    f64_ge, // ...

    //
    // arithmetic
    //
    i32_add,      // fn (left, right) -> value
    i32_sub,      // ...
    i32_mul,      // ...
    i32_mul_hi_s, // ...
    i32_mul_hi_u, // ...
    i32_div_s,    // ...
    i32_div_u,    // ...
    i32_rem_s,    // ...
    i32_rem_u,    // ...
    i32_inc,      // fn (num, imm) -> value
    i32_dec,      // fn (num, imm) -> value

    i64_add,      // fn (left, right) -> value
    i64_sub,      // ...
    i64_mul,      // ...
    i64_mul_hi_s, // ...
    i64_mul_hi_u, // ...
    i64_div_s,    // ...
    i64_div_u,    // ...
    i64_rem_s,    // ...
    i64_rem_u,    // ...
    i64_inc,      // fn (num, imm) -> value
    i64_dec,      // fn (num, imm) -> value

    f32_add, // fn (left, right) -> value
    f32_sub, // ...
    f32_mul, // ...
    f32_div, // ...

    f64_add, // fn (left, right) -> value
    f64_sub, // ...
    f64_mul, // ...
    f64_div, // ...

    //
    // bitwise
    //
    i32_and,            // fn (left, right) -> value
    i32_or,             // ...
    i32_xor,            // ...
    i32_shift_left,     // fn (src, num) -> value
    i32_shift_right_s,  // ...
    i32_shift_right_u,  // ...
    i32_rotate_left,    // ...
    i32_rotate_right,   // ...
    i32_not,            // fn (src) -> value
    i32_leading_zeros,  // ...
    i32_leading_ones,   // ...
    i32_trailing_zeros, // ...
    i32_count_ones,     // ...

    i64_and,            // fn (left, right) -> value
    i64_or,             // ...
    i64_xor,            // ...
    i64_shift_left,     // fn (src, num) -> value
    i64_shift_right_s,  // ...
    i64_shift_right_u,  // ...
    i64_rotate_left,    // ...
    i64_rotate_right,   // ...
    i64_not,            // fn (src) -> value
    i64_leading_zeros,  // ...
    i64_leading_ones,   // ...
    i64_trailing_zeros, // ...
    i64_count_ones,     // ...

    //
    // math
    //
    i32_abs, // fn (src) -> value
    i32_neg, // ...

    i64_abs, // fn (src) -> value
    i64_neg, // ...

    f32_abs,                // fn (src) -> value
    f32_neg,                // ...
    f32_ceil,               // ...
    f32_floor,              // ...
    f32_round_half_to_even, // ...
    f32_trunc,              // ...
    f32_sqrt,               // ...
    f32_copysign,           // fn (src, sign) -> value
    f32_min,                // fn (left, right) -> value
    f32_max,                // ...

    f64_abs,                // fn (src) -> value
    f64_neg,                // ...
    f64_ceil,               // ...
    f64_floor,              // ...
    f64_round_half_to_even, // ...
    f64_trunc,              // ...
    f64_sqrt,               // ...
    f64_copysign,           // fn (src, sign) -> value
    f64_min,                // fn (left, right) -> value
    f64_max,                // ...

    //
    // function call
    //
    // call,    // fn ($func_name, arg0, arg1, ...) -> value{0,}
    // dyncall, // fn (func_addr, arg0, arg1, ...) -> value{0,}
    // syscall, // fn (syscall_num, arg0, arg1, ...) -> value

    //
    // machine
    //
    trap, // fn (num)

    //
    // memory address
    //
    addr_local,             // fn ($local_name, offset) -> value
    addr_data,              // fn ($data_name, offset) -> value
    addr_thread_local_data, // fn ($data_name, offset) -> value
    addr_function,          // fn ($func_name) -> value
    addr_fp,                // fn () -> value
    addr_sp,                // fn () -> value
    addr_return,            // fn () -> value

    //
    // atomic
    //
    i32_atomic_rmw_add,      // fn (addr, value) -> old_value
    i32_atomic_rmw_sub,      // ...
    i32_atomic_rmw_and,      // ...
    i32_atomic_rmw_or,       // ...
    i32_atomic_rmw_xor,      // ...
    i32_atomic_rmw_exchange, // ...
    i32_atomic_cas,          // fn (addr, expect_value, new_value) -> old_value

    i64_atomic_rmw_add,      // fn (addr, value) -> old_value
    i64_atomic_rmw_sub,      // ...
    i64_atomic_rmw_and,      // ...
    i64_atomic_rmw_or,       // ...
    i64_atomic_rmw_xor,      // ...
    i64_atomic_rmw_exchange, // ...
    i64_atomic_cas,          // fn (addr, expect_value, new_value) -> old_value

    //
    // SIMD/Vectorization
    //
    // todo
}
